<?php

namespace App\Entity;

use App\Repository\AdminRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity(repositoryClass=AdminRepository::class)
 * @ORM\HasLifecycleCallbacks()
 * @UniqueEntity(fields={"username"}, message="There is already an account with this username")
 */
class Admin implements UserInterface,EquatableInterface, \Serializable
{
    const ROLE_DEFAULT = 'ROLE_USER';        //普通账号
    const ROLE_ADMIN = 'ROLE_ADMIN';        //管理员
    const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';  //超级管理员

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, unique=true)
     * @Assert\NotBlank(message="登录账号不能为空")
     * @Assert\Length(min=6, max=20,minMessage="登录账号不能小于6字符",maxMessage="登录账号不能大于20个字符")
     */
    private $username;

    /**
     * @ORM\Column(type="json")
     */
    private $roles = [self::ROLE_DEFAULT];

    /**
     * @var string The hashed password
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\Column(type="datetime")
     */
    private $created;

    /**
     * @ORM\Column(type="datetime",nullable=true)
     */
    private $lastLoginDate;

    /**
     * @ORM\Column(type="string", length=50, nullable=true)
     * @Assert\Length(min=6, max=20,minMessage="密码不能小于6字符",maxMessage="密码不能大于20个字符")
     */
    private $plainPassword;

    /**
     * @ORM\Column(type="boolean")
     */
    private $enabled=false;

    public function __toString()
    {
        return $this->getUsername();
    }

    public function preSetValue(){
        $this->setCreated(new \DateTime());
    }

    public function isEqualTo(UserInterface $user)
    {
        if (!$user instanceof self) return false;

        if ($this->getPassword() !== $user->getPassword()) return false;

        if ($this->getUsername() !== $user->getUsername()) return false;

        if ($this->isEnabled() !== $user->isEnabled()) return false;

        return true;
    }

    /**
     * 获得全部权限（注：权限添加时请权限从大到小排列）
     * @return array
     */
    private function getSortedRoles(){
        $sorted=array(
            self::ROLE_SUPER_ADMIN=>'超级管理',
            self::ROLE_ADMIN=>'管理员',
            self::ROLE_DEFAULT=>'个人账号'
        );
        return $sorted;
    }

    /**
     * 比较权限的高低
     * @param string $r1 权限常量名
     * @param string $r2 权限常量名
     * @return int
     */
    public static function cmpRole($r1,$r2){
        $sorted=array(
            self::ROLE_SUPER_ADMIN=>9999,
            self::ROLE_ADMIN=>999,
            self::ROLE_DEFAULT=>0
        );
        return bccomp($sorted[$r1], $sorted[$r2]);
    }

    /**
     * 该用户可以分配的角色权限
     * @return array
     */
    public function getCanAssignRoles(){
        $roles=array();
        $topRole=$this->getTopRole();
        $sortedRoles=$this->getSortedRoles();
        unset($sortedRoles[self::ROLE_DEFAULT]);
        $sortedRoles=array_keys($sortedRoles);
        $index=array_search($topRole, $sortedRoles);
        $roles = array_slice($sortedRoles, $index+1);
        return $roles;
    }

    /**
     * 获得最大权限的常量名
     * @return null
     */
    public function getTopRole() {
        $roles=$this->getRoles();
        $sortedRoles=array_keys($this->getSortedRoles());
        foreach ($sortedRoles as $role) {
            if(in_array($role, $roles)){
                return $role;
            }
        }
        return null;
    }

    /**
     * 获得指定权限的可读名称
     * @param string $role 权限名称
     * @return mixed|null
     */
    public function getRoleHuman($role){
        $mapped=$this->getSortedRoles();
        if(isset($mapped[$role])){
            return $mapped[$role];
        }
        return null;
    }

    /**
     * 获得最大的权限可读名称
     * @return string
     */
    public function getTopRoleHuman(){
        $role=$this->getTopRole();
        $role_human=$this->getRoleHuman($role);
        if(isset($role_human)){
            return $role_human;
        }
        return "匿名";
    }


    /** @see \Serializable::serialize() */
    public function serialize()
    {
        return serialize(array(
            $this->id,
            $this->username,
            $this->password,
            $this->enabled,
            // see section on salt below
            // $this->salt,
        ));
    }

    /** @see \Serializable::unserialize() */
    public function unserialize($serialized)
    {
        list (
            $this->id,
            $this->username,
            $this->password,
            $this->enabled,
            // see section on salt below
            // $this->salt
            ) = unserialize($serialized);
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUsername(): string
    {
        return (string) $this->username;
    }

    public function setUsername(string $username): self
    {
        $this->username = $username;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles = $roles?:[self::ROLE_DEFAULT];

        return array_unique($roles);
    }

    public function setRoles(array $roles): self
    {
        $this->roles = $roles?:[self::ROLE_DEFAULT];

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getPassword(): string
    {
        return (string) $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getSalt()
    {
        // not needed when using the "bcrypt" algorithm in security.yaml
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        // If you store any temporary, sensitive data on the user, clear it here
         $this->plainPassword = null;
    }

    public function getCreated(): ?\DateTimeInterface
    {
        return $this->created;
    }

    public function setCreated(\DateTimeInterface $created): self
    {
        $this->created = $created;

        return $this;
    }

    public function getLastLoginDate(): ?\DateTimeInterface
    {
        return $this->lastLoginDate;
    }

    public function setLastLoginDate(\DateTimeInterface $lastLoginDate): self
    {
        $this->lastLoginDate = $lastLoginDate;

        return $this;
    }

    public function getPlainPassword(): ?string
    {
        return $this->plainPassword;
    }

    public function setPlainPassword(?string $plainPassword): self
    {
        $this->plainPassword = $plainPassword;

        return $this;
    }

    public function isEnabled()
    {
        return $this->enabled;
    }

    public function setEnabled(bool $enabled): self
    {
        $this->enabled = $enabled;

        return $this;
    }
}
